/**
 *    Copyright (C) 2008, 2009  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_TOOLS_TYPES_RELATION_EXPRESSION_HPP
#define	_CUBEFS_CORE_TOOLS_TYPES_RELATION_EXPRESSION_HPP

#include <cubefs/core/tools/types/typemap.hpp>


namespace cubefs    {
namespace tools     {


enum CompareOps {EQ, GT, GTE, LT, LTE, NE};

template <Int Name_, CompareOps Op_, typename T, T Value_>
struct ValueOp {
    static const Int Name           = Name_;
    typedef T                       Type;
    static const CompareOps Op      = Op_;
    static const T Value            = Value_;
};

struct TrueOp {};

template <Int Name_, typename T>
struct TypeOp {
    static const Int Name           = Name_;
    typedef T                       Type;
};

template <typename T1, typename T2>
struct And {
    typedef T1 Type1;
    typedef T2 Type2;
};

template <typename T1, typename T2>
struct Or {
    typedef T1 Type1;
    typedef T2 Type2;
};

template <typename T1, typename T2>
struct Xor {
    typedef T1 Type1;
    typedef T2 Type2;
};

template <typename T>
struct Not {
    typedef T Type;
};



template<typename Type>
struct IsExpression: public FalseValue {};

template<typename T1, typename T2>
struct IsExpression<And<T1, T2> >: public TrueValue {};

template<typename T1, typename T2>
struct IsExpression<Or<T1, T2> >: public TrueValue {};

template<typename T1, typename T2>
struct IsExpression<Xor<T1, T2> >: public TrueValue {};

template<typename T>
struct IsExpression<Not<T> >: public TrueValue {};

template<Int Name, CompareOps Op, typename T, T Value>
struct IsExpression<ValueOp<Name, Op, T, Value> >: public TrueValue {};

template<Int Name, typename T>
struct IsExpression<TypeOp<Name, T> >: public TrueValue {};

template<>
struct IsExpression<TrueOp>: public TrueValue {};






template <typename Metadata, typename Expr, typename Record> class Evaluator;

template <typename Metadata, typename Type1, typename Type2, typename Record>
class Evaluator<Metadata, And<Type1, Type2>, Record> {
public:
    static const bool Value =   Evaluator<Metadata, Type1, Record>::Value &&
                                Evaluator<Metadata, Type2, Record>::Value;
};


template <typename Metadata, typename Type1, typename Type2, typename Record>
class Evaluator<Metadata, Or<Type1, Type2>, Record> {
public:
    static const bool Value =   Evaluator<Metadata, Type1, Record>::Value ||
                                Evaluator<Metadata, Type2, Record>::Value;
};

template <typename Metadata, typename Type1, typename Type2, typename Record>
class Evaluator<Metadata, Xor<Type1, Type2>, Record> {
public:
    static const bool Value =   Evaluator<Metadata, Type1, Record>::Value ^
                                Evaluator<Metadata, Type2, Record>::Value;
};

template <typename Metadata, typename Type, typename Record>
class Evaluator<Metadata, Not<Type>, Record> {
public:
    static const bool Value =  !Evaluator<Metadata, Type, Record>::Value;
};


template <typename Metadata, Int Name, CompareOps Op, typename Type, Type ExValue, typename Record>
class Evaluator<Metadata, ValueOp<Name, Op, Type, ExValue>, Record> {

    typedef typename Metadata::template Provider<Name, Record>::Value           ColumnValue;

    static const bool GTVal     =  ColumnValue::Value >  ExValue;
    static const bool GTEVal    =  ColumnValue::Value >= ExValue;

    static const Int OpIdx = Op;

    typedef typename Select<
                OpIdx,
                typename TypeListTool<
                    TypeCode<ColumnValue::Value == ExValue>,
                    TypeCode<GTVal>,
                    TypeCode<GTEVal>,
                    TypeCode<ColumnValue::Value <  ExValue>,
                    TypeCode<ColumnValue::Value <= ExValue>,
                    TypeCode<ColumnValue::Value != ExValue>
                >::List
    >::Result                                                                   SelectResult;


public:
    static const bool Value = SelectResult::Value;
};

template <typename Metadata, Int Name, typename Type, typename Record>
class Evaluator<Metadata, TypeOp<Name, Type>, Record> {

    typedef typename Metadata::template Provider<Name, Record>::Value::Value    ColumnValue;
    
public:
    static const bool Value = IfTypesEqual<Type, ColumnValue>::Value;
};

template <typename Metadata, typename Record>
class Evaluator<Metadata, TrueOp, Record> {
public:
    static const bool Value = true;
};

}
}

#endif //_CUBEFS_CORE_TOOLS_TYPES_RELATION_EXPRESSION_HPP